package br.edu.ufcg.splab.util;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;

import br.edu.ufcg.splab.core.InterfaceEdge;
import br.edu.ufcg.splab.core.InterfaceGenerate;
import br.edu.ufcg.splab.core.InterfaceGraph;
import br.edu.ufcg.splab.core.graph.Tree;
import br.edu.ufcg.splab.exceptions.LTSBTException;
import br.edu.ufcg.splab.generator.ConvertGraphToTree;
import br.edu.ufcg.splab.generator.TestCase;
import br.edu.ufcg.splab.generator.TestCaseGenerator;
import br.edu.ufcg.splab.generator.TestSuite;
import br.edu.ufcg.splab.parser.GraphToAnnotatedGraphParser;

public class FailuresIdentifier {
	
	protected final String EOL = System.getProperty("line.separator");

	public TestSuite getFailures(TestSuite testSuite, String stretch){
		TestSuite ts = new TestSuite();
		for(TestCase tc: testSuite.getTestSuite()){
			String tc_str = "";
			for(InterfaceEdge edge: tc.getTestCase()){
				if(tc_str.isEmpty()){
					tc_str += edge.getLabel();
				}else{
					tc_str += "#" + edge.getLabel();
				}				
			}
			if(tc_str.contains(stretch)){
				ts.add(tc);
			}
		}		
		return ts;
	}
	
	public void getFailuresFromGraph(String path, String fileNameInput, String fileNameOutput, int numExpand) throws LTSBTException, IOException{
		File fileInput = new File(fileNameInput);
		Scanner scanner = new Scanner(fileInput);
		Map<String, List<String>> faults =  new HashMap<String, List<String>>();		
		String line ="";
		String modelName = "";
		while (scanner.hasNextLine()) {			
			line = scanner.nextLine().trim();		    		    
		   if(line.substring(line.length() - 1).equals(":")) {				
				modelName = line.substring(0, line.length() - 1);
				faults.put(modelName, new ArrayList<String>());
			}else{
				faults.get(modelName).add(line);
			}			
		}
		
		BufferedWriter bufferedOutput =  new BufferedWriter(new FileWriter(new File(fileNameOutput)));

		Set<Entry<String, List<String>>> set = faults.entrySet();		
		Iterator<Entry<String, List<String>>> it = set.iterator();
		while(it.hasNext()){
			Entry<String, List<String>> entry = it.next();
			String graphFile = entry.getKey();
			ReadTGF parser = new ReadTGF();	
			InterfaceGraph graph = parser.getGraph(path + graphFile);
			
			InterfaceGenerate generator = new TestCaseGenerator();
			ConvertGraphToTree convertsGraphToTree = new ConvertGraphToTree();
			Tree tree = convertsGraphToTree.converterGraph(graph);
			tree.expand(numExpand);
			TestSuite testSuite_generated = generator.generate(tree);	
			Controller c = new Controller();
			TestSuite testSuite = c.getValidTS(testSuite_generated);
			System.out.println("testSuite_generated: " + testSuite_generated.getTestSuite().size());
			System.out.println("testSuite: " + testSuite.getTestSuite().size());
			
			MapTestSuite mapTS = new MapTestSuite(testSuite);
			
			FailuresIdentifier failuresIdentifier = new FailuresIdentifier();
			
			List<String> list = entry.getValue();
			bufferedOutput.append(graphFile + ": " + EOL);
			for(String fault:list){
				TestSuite ts = failuresIdentifier.getFailures(testSuite, fault);
				//bufferedOutput.append(fault + ": ");
				for(TestCase tc: ts.getTestSuite()){
					bufferedOutput.append(mapTS.getValueTestCase(tc) + "#");
				}
				bufferedOutput.append(EOL);
			}
		}
		bufferedOutput.close();
		scanner.close();
	}
	
	public Map<String, Map<Integer, List<String>>> getDefects(String fileNameInput) throws IOException{
		
		Map<String, Map<Integer, List<String>>> mapDefects = new HashMap<String, Map<Integer, List<String>>>();
		File fileInput = new File(fileNameInput);
		Scanner scanner = new Scanner(fileInput);
		
		String line ="";
		String modelName = "";
		
		int cont = 1;
		while (scanner.hasNextLine()) {			
			line = scanner.nextLine().trim();		    		    
		   if(line.substring(line.length() - 1).equals(":")) {			
			   	modelName = line.substring(0, line.length() - 1);
			   	mapDefects.put(modelName, new HashMap<Integer, List<String>>());
			   	cont = 1;
			}else{
				List<String> testCases = new ArrayList<String>();
				if(line.contains("#")){					
					Scanner scanner2 = new Scanner(line);
					scanner2.useDelimiter("#");	
					while(scanner2.hasNext()){
						//System.out.print(scanner2.nextLine() + ", ");
						String f = scanner2.next();
						testCases.add(f);
					}		
					mapDefects.get(modelName).put(new Integer(cont), testCases);
					cont++;
					scanner2.close();
				}else{
					testCases.add(line);
					mapDefects.get(modelName).put(new Integer(cont), testCases);
					cont++;
				}
			}			
		}
		
		scanner.close();
		return mapDefects;
	}
	
	
	/**
	 * Gera um arquivo de saida que faz o mapeamento dos casos de teste que falham para cada falta.
	 */
	public Map<String, List<String>> getFailuresFromAnnotatedGraph(String path, String fileNameInput, String fileNameOutput, int numExpand) throws LTSBTException, IOException{
		File fileInput = new File(fileNameInput);
		Scanner scanner = new Scanner(fileInput);
		Map<String, List<String>> faults =  new HashMap<String, List<String>>();		
		String line ="";
		String modelName = "";
		while (scanner.hasNextLine()) {			
			line = scanner.nextLine().trim();		    		    
		   if(line.substring(line.length() - 1).equals(":")) {				
				modelName = line.substring(0, line.length() - 1);
				faults.put(modelName, new ArrayList<String>());
			}else{
				faults.get(modelName).add(line);
			}			
		}
		
		BufferedWriter bufferedOutput =  new BufferedWriter(new FileWriter(new File(fileNameOutput)));

		Set<Entry<String, List<String>>> set = faults.entrySet();		
		Iterator<Entry<String, List<String>>> it = set.iterator();
		while(it.hasNext()){
			Entry<String, List<String>> entry = it.next();
			String graphFile = entry.getKey();
			ReadTGF read = new ReadTGF();
			InterfaceGraph graph = read.getGraph(path + graphFile);
				
			
			GraphToAnnotatedGraphParser convertsAnnotatedGraphToTree = new GraphToAnnotatedGraphParser();
			InterfaceGraph newGraph = null;
			try {
				newGraph = convertsAnnotatedGraphToTree.graphContraction(graph);
			} catch (LTSBTException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
			ConvertGraphToTree convertsGraphToTree = new ConvertGraphToTree();
			Tree tree = convertsGraphToTree.converterGraph(newGraph);
//			Tree tree = convertsGraphToTree.converterGraph(graph);
			
			tree.expand(numExpand);		
			
			
			
			InterfaceGenerate generator = new TestCaseGenerator();		
			TestSuite generatedSuite = generator.generate(tree);
			Controller controller = new Controller();
			TestSuite validTestSuite = controller.getValidTS(generatedSuite);
			System.out.println("validTestSuite: " + validTestSuite.getTestSuite().size());
			
			
						
			MapTestSuite mapTS = new MapTestSuite(generatedSuite);
			
			for(TestCase tc: validTestSuite){
				System.out.println(mapTS.getValueTestCase(tc) + ": " + tc.toString());
			}
			FailuresIdentifier failuresIdentifier = new FailuresIdentifier();
			
			List<String> list = entry.getValue();
			bufferedOutput.append(graphFile + ": " + EOL);
			for(String fault:list){
				//TestSuite ts = failuresIdentifier.getFailures(generatedSuite, fault);
				TestSuite ts = failuresIdentifier.getFailures(validTestSuite, fault);
				//bufferedOutput.append(fault + ": ");
				for(TestCase tc: ts.getTestSuite()){
					bufferedOutput.append(mapTS.getValueTestCase(tc) + "#");
				}
				bufferedOutput.append(EOL);
			}
		}
		bufferedOutput.close();
		scanner.close();
		return faults;
	}
	
	
//	/**
//	 * Gera um arquivo de saida que faz o mapeamento dos casos de teste que falham para cada falta.
//	 */
//	public Map<String, List<String>> getFailuresFromFLP(String path, String fileNameInput, String fileNameOutput, int numExpand) throws LTSBTException, IOException{
//		File fileInput = new File(fileNameInput);
//		Scanner scanner = new Scanner(fileInput);
//		Map<String, List<String>> faults =  new HashMap<String, List<String>>();		
//		String line ="";
//		String modelName = "";
//		while (scanner.hasNextLine()) {			
//			line = scanner.nextLine().trim();		    		    
//		   if(line.substring(line.length() - 1).equals(":")) {				
//				modelName = line.substring(0, line.length() - 1);
//				faults.put(modelName, new ArrayList<String>());
//			}else{
//				faults.get(modelName).add(line);
//			}			
//		}
//		
//		BufferedWriter bufferedOutput =  new BufferedWriter(new FileWriter(new File(fileNameOutput)));
//
//		Set<Entry<String, List<String>>> set = faults.entrySet();		
//		Iterator<Entry<String, List<String>>> it = set.iterator();
//		while(it.hasNext()){
//			Entry<String, List<String>> entry = it.next();
//			String graphFile = entry.getKey();
//			ReadTGF read = new ReadTGF();
//			InterfaceGraph graph = read.getGraph(path + graphFile);
//				
//			
//			GraphToAnnotatedGraphParser convertsAnnotatedGraphToTree = new GraphToAnnotatedGraphParser();
//			InterfaceGraph newGraph = null;
//			try {
//				newGraph = convertsAnnotatedGraphToTree.graphContraction(graph);
//			} catch (LTSBTException e1) {
//				// TODO Auto-generated catch block
//				e1.printStackTrace();
//			}
//			
//	
//			FindLoopingPaths flp = new FindLoopingPaths(newGraph);
//			br.edu.ufcg.splab.flp.Tree tree = flp.unenroll(numExpand);
//			TestSuite generatedSuite = Util.convertTestPathsToTestSuite(tree.testSuite());
//
//			System.out.println("Generated: " + generatedSuite.getTestSuite().size());
//			Controller controller = new Controller();
//			TestSuite validTestSuite = controller.getValidTS(generatedSuite);
//			System.out.println("ValidTestSuite: " + validTestSuite.getTestSuite().size());
//			
//			
//						
//			MapTestSuite mapTS = new MapTestSuite(generatedSuite);
//			
////			for(TestCase tc: validTestSuite){
////				System.out.println(mapTS.getValueTestCase(tc) + ": " + tc.toString());
////			}
//			FailuresIdentifier failuresIdentifier = new FailuresIdentifier();
//			
//			List<String> list = entry.getValue();
//			bufferedOutput.append(graphFile + ": " + EOL);
//			for(String fault:list){
//				//TestSuite ts = failuresIdentifier.getFailures(generatedSuite, fault);
//				TestSuite ts = failuresIdentifier.getFailures(validTestSuite, fault);
//				for(TestCase tc: ts.getTestSuite()){
//					bufferedOutput.append(mapTS.getValueTestCase(tc) + "#");
//				}
//				bufferedOutput.append(EOL);
//			}
//		}
//		bufferedOutput.close();
//		scanner.close();
//		return faults;
//	}
//	
//	public Map<String, List<String>> getFailuresFromFLP2(String path, String fileNameInput, String fileNameOutput, int numExpand) throws LTSBTException, IOException{
//		File fileInput = new File(fileNameInput);
//		Scanner scanner = new Scanner(fileInput);
//		Map<String, List<String>> faults =  new HashMap<String, List<String>>();		
//		String line ="";
//		String modelName = "";
//		while (scanner.hasNextLine()) {			
//			line = scanner.nextLine().trim();		    		    
//		   if(line.substring(line.length() - 1).equals(":")) {				
//				modelName = line.substring(0, line.length() - 1);
//				faults.put(modelName, new ArrayList<String>());
//			}else{
//				faults.get(modelName).add(line);
//			}			
//		}
//		
//		BufferedWriter bufferedOutput =  new BufferedWriter(new FileWriter(new File(fileNameOutput)));
//
//		Set<Entry<String, List<String>>> set = faults.entrySet();		
//		Iterator<Entry<String, List<String>>> it = set.iterator();
//		while(it.hasNext()){
//			Entry<String, List<String>> entry = it.next();
//			String graphFile = entry.getKey();
//			ReadTGF read = new ReadTGF();
//			InterfaceGraph graph = read.getGraph(path + graphFile);
//				
//				
//	
//			FindLoopingPaths flp = new FindLoopingPaths(graph);
//			br.edu.ufcg.splab.flp.Tree tree = flp.unenroll(numExpand);
//			TestSuite generatedSuite = Util.convertTestPathsToTestSuite(tree.testSuite());
//
//			System.out.println("Generated: " + generatedSuite.getTestSuite().size());
//			Controller controller = new Controller();
//			TestSuite validTestSuite = controller.getValidTS(generatedSuite);
//			System.out.println("ValidTestSuite: " + validTestSuite.getTestSuite().size());
//			
//			
//						
//			MapTestSuite mapTS = new MapTestSuite(generatedSuite);
//			
////			for(TestCase tc: validTestSuite){
////				System.out.println(mapTS.getValueTestCase(tc) + ": " + tc.toString());
////			}
//			FailuresIdentifier failuresIdentifier = new FailuresIdentifier();
//			
//			List<String> list = entry.getValue();
//			bufferedOutput.append(graphFile + ": " + EOL);
//			for(String fault:list){
//				//TestSuite ts = failuresIdentifier.getFailures(generatedSuite, fault);
//				TestSuite ts = failuresIdentifier.getFailures(validTestSuite, fault);
//				//bufferedOutput.append(fault + ": ");
//				for(TestCase tc: ts.getTestSuite()){
//					bufferedOutput.append(mapTS.getValueTestCase(tc) + "#");
//				}
//				bufferedOutput.append(EOL);
//			}
//		}
//		bufferedOutput.close();
//		scanner.close();
//		return faults;
//	}
	
	/**
	 * Gera um map com os dados da sa�da do m�todo getFailuresFromAnnotatedGraph (acima).
	 */
	public Map<String, Map<String, List<Integer>>> getFailuresFromAnnotatedGraph(String path, String fileNameInput, int numExpand) throws LTSBTException, IOException{
		File fileInput = new File(fileNameInput);
		Scanner scanner = new Scanner(fileInput);
		Map<String, List<String>> faults =  new HashMap<String, List<String>>();		
		String line ="";
		String modelName = "";
		while (scanner.hasNextLine()) {			
			line = scanner.nextLine().trim();		    		    
		   if(line.substring(line.length() - 1).equals(":")) {				
				modelName = line.substring(0, line.length() - 1);
				faults.put(modelName, new ArrayList<String>());
			}else{
				faults.get(modelName).add(line);
			}			
		}
		
		//BufferedWriter bufferedOutput =  new BufferedWriter(new FileWriter(new File(fileNameOutput)));

		Set<Entry<String, List<String>>> set = faults.entrySet();		
		Iterator<Entry<String, List<String>>> it = set.iterator();
		
		Map<String, Map<String, List<Integer>>> allFailures =  new HashMap<String, Map<String, List<Integer>>>();
		
		while(it.hasNext()){
			Entry<String, List<String>> entry = it.next();
			String graphFile = entry.getKey();
			ReadTGF read = new ReadTGF();
			InterfaceGraph graph = read.getGraph(path + graphFile);
			GraphToAnnotatedGraphParser convertsAnnotatedGraphToTree = new GraphToAnnotatedGraphParser();
			InterfaceGraph newGraph = null;
			try {
				newGraph = convertsAnnotatedGraphToTree.graphContraction(graph);
			} catch (LTSBTException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
			ConvertGraphToTree convertsGraphToTree = new ConvertGraphToTree();
			Tree tree = convertsGraphToTree.converterGraph(newGraph);
			
			tree.expand(numExpand);		
			
			InterfaceGenerate generator = new TestCaseGenerator();		
			TestSuite generatedSuite = generator.generate(tree);
			Controller controller = new Controller();
			TestSuite validTestSuite = controller.getValidTS(generatedSuite);
						
			MapTestSuite mapTS = new MapTestSuite(generatedSuite);
			
			FailuresIdentifier failuresIdentifier = new FailuresIdentifier();
			Map<String, List<Integer>> failures = new HashMap<String, List<Integer>>();
			 
			
			List<String> list = entry.getValue();
			List<Integer> testCases = new ArrayList<Integer>();
			for(String fault:list){
				//TestSuite ts = failuresIdentifier.getFailures(generatedSuite, fault);
				TestSuite ts = failuresIdentifier.getFailures(validTestSuite, fault);
				for(TestCase tc: ts.getTestSuite()){
					testCases.add(mapTS.getValueTestCase(tc));
				}
				failures.put(fault, testCases);
			}
			allFailures.put(graphFile, failures);
		}
		scanner.close();
		return allFailures;
	}
	
	public Map<String, Map<Integer, List<String>>> getFailuresFromAnnotatedGraph2(String path, String fileNameInput, int numExpand) throws LTSBTException, IOException{
		File fileInput = new File(fileNameInput);
		Scanner scanner = new Scanner(fileInput);
		Map<String, List<String>> faults =  new HashMap<String, List<String>>();		
		String line ="";
		String modelName = "";
		while (scanner.hasNextLine()) {			
			line = scanner.nextLine().trim();		    		    
		   if(line.substring(line.length() - 1).equals(":")) {				
				modelName = line.substring(0, line.length() - 1);
				faults.put(modelName, new ArrayList<String>());
			}else{
				faults.get(modelName).add(line);
			}			
		}
		
		Set<Entry<String, List<String>>> set = faults.entrySet();		
		Iterator<Entry<String, List<String>>> it = set.iterator();
		
		Map<String, Map<Integer, List<String>>> allFailures =  new HashMap<String, Map<Integer, List<String>>>();
		
		while(it.hasNext()){
			Entry<String, List<String>> entry = it.next();
			String graphFile = entry.getKey();
			ReadTGF read = new ReadTGF();
			InterfaceGraph graph = read.getGraph(path + graphFile);
			GraphToAnnotatedGraphParser convertsAnnotatedGraphToTree = new GraphToAnnotatedGraphParser();
			InterfaceGraph newGraph = null;
			try {
				newGraph = convertsAnnotatedGraphToTree.graphContraction(graph);
			} catch (LTSBTException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
			ConvertGraphToTree convertsGraphToTree = new ConvertGraphToTree();
			Tree tree = convertsGraphToTree.converterGraph(newGraph);
			
			tree.expand(numExpand);		
			
			InterfaceGenerate generator = new TestCaseGenerator();		
			TestSuite generatedSuite = generator.generate(tree);
			Controller controller = new Controller();
			TestSuite validTestSuite = controller.getValidTS(generatedSuite);
						
			MapTestSuite mapTS = new MapTestSuite(generatedSuite);
			
			FailuresIdentifier failuresIdentifier = new FailuresIdentifier();
			Map<Integer, List<String>> failures = new HashMap<Integer, List<String>>();
			 
			
			List<String> list = entry.getValue();
			List<String> testCases = new ArrayList<String>();
			for(String fault:list){
				TestSuite ts = failuresIdentifier.getFailures(validTestSuite, fault);
				for(TestCase tc: ts.getTestSuite()){
					testCases.add(mapTS.getValueTestCase(tc)+"");
				}
				failures.put(Integer.parseInt(fault), testCases);
			}
			allFailures.put(graphFile, failures);
		}
		scanner.close();
		return allFailures;
	}

	/**
	 * Faz um mapeamento de cada modelo tgf para cada falta como sendo uma lista de String.
	 * 
	 * Exemplo: suponha que temos os modelos model1.tgf e model2.tgf 
	 * O model1.tgf tem as seguintes faltas: a#b#c e b#d#e e o model2.tgf tem a falta x#y#z
	 * O map retornado será:
	 * 
	 * Key
	 * model1.tgf -> <<a,b,c>,<b,d,e>>
	 * model2.tgf -> <<x,y,z>>
	 */
	public Map<String, List<List<String>>> getFaults(String fileNameInput) throws FileNotFoundException{
		File fileInput = new File(fileNameInput);
		Scanner scanner = new Scanner(fileInput);
		Map<String, List<List<String>>> failures =  new HashMap<String, List<List<String>>>();		
		String line ="";
		String modelName = "";
		while (scanner.hasNextLine()) {			
		   line = scanner.nextLine().trim();		    		    
		   if(line.substring(line.length() - 1).equals(":")) {				
				modelName = line.substring(0, line.length() - 1);
				failures.put(modelName, new ArrayList<List<String>>());
			}else{
				Scanner scanner2 = new Scanner(line);
				scanner2.useDelimiter("#");
				List<String> listFailure = new ArrayList<String>();
				while(scanner2.hasNext()){
					listFailure.add(scanner2.next());
				}
				failures.get(modelName).add(listFailure);
				scanner2.close();
			}			
		}
		scanner.close();
		return failures;
	}	

}
